#!/usr/bin/env python3
"""
Prometheus 告警分析主程序
支持定时监控、AI分析和智能通知
"""

import os
import sys
import time
import logging
import argparse
import signal
from typing import Dict, List, Any
from datetime import datetime, timedelta

# 添加项目根目录到路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from config import Config
from database import PrometheusConnector
from analyzer import PrometheusAlertAnalyzer
from notification import PrometheusNotifier
from utils import LogUtils

class PrometheusMonitor:
    """Prometheus 监控主程序"""
    
    def __init__(self):
        """初始化监控器"""
        self.config = Config()
        self.logger = self._setup_logger()
        self.db = PrometheusConnector()
        self.analyzer = PrometheusAlertAnalyzer()
        self.notification = PrometheusNotifier()
        self.running = True
        
        # 告警状态跟踪
        self.last_alert_check = None
        self.alert_history = {}
        
        # 设置信号处理
        signal.signal(signal.SIGINT, self._signal_handler)
        signal.signal(signal.SIGTERM, self._signal_handler)
    
    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器"""
        log_config = self.config.get_logging_config()
        
        # 使用根logger保持与Zabbix一致的格式
        logger = logging.getLogger()
        logger.setLevel(getattr(logging, log_config['log_level']))
        
        # 避免重复添加处理器
        if not logger.handlers:
            # 控制台处理器
            console_handler = logging.StreamHandler()
            console_handler.setLevel(getattr(logging, log_config['log_level']))
            console_formatter = logging.Formatter(
                '%(asctime)s - %(levelname)s - %(message)s'  # 与Zabbix保持一致
            )
            console_handler.setFormatter(console_formatter)
            logger.addHandler(console_handler)
            
            # 文件处理器
            if log_config.get('log_file'):
                os.makedirs(os.path.dirname(log_config['log_file']), exist_ok=True)
                file_handler = logging.FileHandler(log_config['log_file'])
                file_handler.setLevel(getattr(logging, log_config['log_level']))
                file_formatter = logging.Formatter(
                    '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
                )
                file_handler.setFormatter(file_formatter)
                logger.addHandler(file_handler)
        
        return logger
    
    def _signal_handler(self, signum, frame):
        """信号处理器"""
        self.logger.info(f"接收到信号 {signum}，准备优雅关闭...")
        self.running = False
    
    def check_connection(self) -> bool:
        """检查连接状态"""
        LogUtils.log_operation_start("连接Prometheus")
        
        try:
            prometheus_config = self.config.get_prometheus_config()
            prometheus_url = prometheus_config.get('url', 'localhost:9090')
            
            if not self.db.test_connection():
                LogUtils.log_operation_error("连接Prometheus", f"连接失败: {prometheus_url}")
                return False
            
            LogUtils.log_operation_success("连接Prometheus")
            return True
            
        except Exception as e:
            LogUtils.log_operation_error("连接Prometheus", str(e))
            return False
    
    def process_alerts(self) -> Dict[str, Any]:
        """处理告警信息"""
        try:
            # 获取活跃告警
            LogUtils.log_operation_start("获取告警数据")
            alerts = self.db.get_active_alerts()
            
            if not alerts:
                self.logger.debug("没有活跃告警")
                LogUtils.log_alert_stats(0)
                return {
                    'success': True,
                    'alert_count': 0,
                    'message': '没有活跃告警'
                }
            
            LogUtils.log_alert_stats(len(alerts))
            LogUtils.log_operation_success("获取告警数据")
            
            # 分析告警
            LogUtils.log_operation_start("分析告警数据")
            
            analysis_result = self.analyzer.analyze_alerts(alerts)
            
            LogUtils.log_operation_success("分析告警数据")
            
            # 检查是否需要发送通知
            should_notify = self._should_send_notification(alerts, analysis_result)
            
            if should_notify:
                # 发送通知
                LogUtils.log_operation_start("发送告警报告")
                
                if isinstance(analysis_result, tuple):
                    analysis_text, ai_success = analysis_result
                else:
                    analysis_text = analysis_result
                    ai_success = True
                    
                notify_success = self.notification.send_analysis_report(
                    analysis_result=analysis_text,
                    alert_count=len(alerts),
                    ai_success=ai_success
                )
                
                LogUtils.log_notification_result(notify_success, len(alerts))
                
                if notify_success:
                    # 更新通知历史
                    self._update_notification_history(alerts)
                    
            else:
                self.logger.debug("根据策略跳过通知发送")
            
            return {
                'success': True,
                'alert_count': len(alerts),
                'analysis': analysis_result,
                'notification_sent': should_notify
            }
            
        except Exception as e:
            LogUtils.log_operation_error("处理告警", str(e))
            # 记录详细错误信息
            self.logger.error(f"处理过程中发生错误: {e}")
            return {
                'success': False,
                'error': str(e),
                'alert_count': 0
            }
    
    def _should_send_notification(self, alerts: List[Dict[str, Any]], analysis: Dict[str, Any]) -> bool:
        """判断是否应该发送通知"""
        try:
            notification_config = self.config.get_notification_config()
            
            # 检查通知间隔
            if self.last_alert_check:
                time_since_last = datetime.now() - self.last_alert_check
                min_interval = timedelta(minutes=notification_config.get('min_interval_minutes', 5))
                
                if time_since_last < min_interval:
                    return False
            
            # 检查告警风暴
            alert_count = len(alerts)
            if alert_count > notification_config.get('alert_storm_threshold', 50):
                # 告警风暴情况下，只发送高优先级告警
                high_priority_count = sum(1 for alert in alerts 
                                        if self._is_high_priority_alert(alert))
                
                if high_priority_count == 0:
                    return False
            
            # 检查告警去重
            current_alert_signature = self._generate_alert_signature(alerts)
            if current_alert_signature in self.alert_history:
                last_sent = self.alert_history[current_alert_signature]
                time_since_last_sent = datetime.now() - last_sent
                
                # 相同告警1小时内不重复发送
                if time_since_last_sent < timedelta(hours=1):
                    return False
            
            return True
            
        except Exception as e:
            self.logger.error(f"判断通知发送策略失败: {e}")
            return True  # 出错时默认发送
    
    def _is_high_priority_alert(self, alert: Dict[str, Any]) -> bool:
        """判断是否为高优先级告警"""
        alert_name = alert.get('alert_name', '').lower()
        
        # 高优先级告警类型
        high_priority_patterns = [
            'instancedown', 'nodedown', 'targetdown',
            'diskfull', 'outofmemory', 'highcpu',
            'serviceunavailable', 'databasedown'
        ]
        
        return any(pattern in alert_name for pattern in high_priority_patterns)
    
    def _generate_alert_signature(self, alerts: List[Dict[str, Any]]) -> str:
        """生成告警签名用于去重"""
        alert_names = sorted([alert.get('alert_name', '') for alert in alerts])
        return '|'.join(alert_names)
    
    def _update_notification_history(self, alerts: List[Dict[str, Any]]):
        """更新通知历史"""
        signature = self._generate_alert_signature(alerts)
        self.alert_history[signature] = datetime.now()
        
        # 清理过期历史（保留24小时）
        cutoff_time = datetime.now() - timedelta(hours=24)
        self.alert_history = {
            sig: timestamp for sig, timestamp in self.alert_history.items()
            if timestamp > cutoff_time
        }
    
    def run_once(self) -> Dict[str, Any]:
        """执行一次检查"""
        start_time = datetime.now()
        LogUtils.log_operation_start("Prometheus告警分析汇报")
        
        # 配置验证
        api_config = self.config.get_api_config()
        ai_engine = api_config.get('ai_engine', 'deepseek')
        LogUtils.log_config_validation(ai_engine)
        
        # 检查连接
        if not self.check_connection():
            return {
                'success': False,
                'error': 'Prometheus连接失败',
                'execution_time': (datetime.now() - start_time).total_seconds()
            }
        
        # 处理告警
        result = self.process_alerts()
        result['execution_time'] = (datetime.now() - start_time).total_seconds()
        
        self.last_alert_check = datetime.now()
        
        if result['success']:
            LogUtils.log_task_completion("Prometheus告警分析汇报")
        
        # 记录执行结束
        self.logger.info("Prometheus连接已关闭")
        
        return result
    
    def run_daemon(self, interval_minutes: int = 5):
        """以守护进程模式运行"""
        self.logger.info(f"启动守护进程模式，检查间隔: {interval_minutes} 分钟")
        
        while self.running:
            try:
                result = self.run_once()
                
                if result['success']:
                    self.logger.debug(f"检查完成 - 告警数量: {result.get('alert_count', 0)}")
                else:
                    self.logger.error(f"检查失败: {result.get('error', 'Unknown error')}")
                
                # 等待下次检查
                sleep_time = interval_minutes * 60
                for _ in range(sleep_time):
                    if not self.running:
                        break
                    time.sleep(1)
                    
            except KeyboardInterrupt:
                self.logger.info("收到中断信号，停止运行")
                break
            except Exception as e:
                self.logger.error(f"守护进程执行出错: {e}")
                time.sleep(60)  # 出错后等待1分钟再重试
        
        self.logger.info("守护进程已停止")

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='Prometheus 告警监控分析系统')
    parser.add_argument('--mode', choices=['once', 'daemon'], default='once',
                       help='运行模式: once(单次执行) 或 daemon(守护进程)')
    parser.add_argument('--interval', type=int, default=5,
                       help='守护进程模式下的检查间隔(分钟), 默认5分钟')
    parser.add_argument('--test-connection', action='store_true',
                       help='测试Prometheus连接')
    parser.add_argument('--verbose', '-v', action='store_true',
                       help='详细输出')
    
    args = parser.parse_args()
    
    # 创建监控器
    monitor = PrometheusMonitor()
    
    # 设置日志级别
    if args.verbose:
        monitor.logger.setLevel(logging.DEBUG)
    
    try:
        if args.test_connection:
            # 测试连接
            print("正在测试Prometheus连接...")
            if monitor.check_connection():
                print("✅ Prometheus连接成功")
                sys.exit(0)
            else:
                print("❌ Prometheus连接失败")
                sys.exit(1)
        
        if args.mode == 'once':
            # 单次执行
            result = monitor.run_once()
            
            if result['success']:
                print(f"✅ 执行成功")
                print(f"   告警数量: {result.get('alert_count', 0)}")
                print(f"   执行时间: {result.get('execution_time', 0):.2f}秒")
                if result.get('notification_sent'):
                    print("   📤 已发送通知")
                sys.exit(0)
            else:
                print(f"❌ 执行失败: {result.get('error', 'Unknown error')}")
                sys.exit(1)
        
        elif args.mode == 'daemon':
            # 守护进程模式
            monitor.run_daemon(args.interval)
            
    except KeyboardInterrupt:
        print("\n收到中断信号，程序退出")
        sys.exit(0)
    except Exception as e:
        print(f"程序执行出错: {e}")
        sys.exit(1)

if __name__ == '__main__':
    main()